package com.maixy.studyonlineapi.redis.template;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * key value redisTemplate
 * Created by jason on 17-3-29.
 */
@Component
public class ValueRedisTemplate extends BaseRedisTemplate {

    public final Logger logger = LoggerFactory.getLogger(ValueRedisTemplate.class);

    @Resource(name = "redisTemplate")
    private RedisTemplate<String, String> redisTemplate;

    public String get(String key) {
        try {
            return redisTemplate.opsForValue().get(key);
        }catch (Exception e) {
            logger.error("redis error", e);
            return null;
        }
    }

    public void set(String key, String value, long timeout) {
        if (value == null || timeout == 0) {
            return;
        }
        try {
            redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
        } catch (Exception e) {
            logger.error("redis error, key={}, value={}, timeout={}", key, value, timeout, e);
        }
    }

    public void set(String key, String value) {
        if (value == null) {
            return;
        }
        try {
            redisTemplate.opsForValue().set(key, value);
        } catch (Exception e) {
            logger.error("redis error, key={}, value={}", key, value, e);
        }
    }

    public Long incr(String key) {
        try {
            return redisTemplate.opsForValue().increment(key, 1);
        }catch (Exception e) {
            logger.error("redis error", e);
            return null;
        }
    }

    public Long incrBy(String key, Long num) {
        try {
            return redisTemplate.opsForValue().increment(key, num);
        }catch (Exception e) {
            logger.error("redis error", e);
            return null;
        }
    }

    public Double incrBy(String key, Double num) {
        try {
            return redisTemplate.opsForValue().increment(key, num);
        }catch (Exception e) {
            logger.error("redis error", e);
            return null;
        }
    }

    public boolean setnx(String key, String value) {
        return redisTemplate.opsForValue().setIfAbsent(key, value);
    }

    public boolean setnx(String key, String value, Long expire) {
        boolean isSuccess = redisTemplate.opsForValue().setIfAbsent(key, value);
        redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        return isSuccess;
    }

    public boolean setnxExpireSuccess(String key, String value, Long expire) {
        boolean isSuccess = redisTemplate.opsForValue().setIfAbsent(key, value);
        if (isSuccess) {
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
        return isSuccess;
    }

    public void setObject(String key, Object value) {
        redisTemplate.opsForValue().set(key, JSON.toJSONString(value));
    }

    /**
     * 字符串转对象
     * @param key
     * @param className
     * @return
     */
    public Object getObject(String key, Class className) {
        String objectString = get(key);
        if(objectString == null) {
            return null;
        }
        Object result = JSON.parseObject(objectString, className);
        return result;
    }

    public void setObject(String key, Object value, long timeout) {
        redisTemplate.opsForValue().set(key, JSON.toJSONString(value), timeout, TimeUnit.SECONDS);
    }

    /**
     * 字符串转对象数组
     * @param key
     * @param clazz
     * @return
     */
    public <T> List<T> getList(String key, Class<T> clazz) {
        String objectString = get(key);
        if (objectString == null) {
            return null;
        } else if ("0".equals(objectString)) {
            return Collections.emptyList();
        }
        return JSON.parseArray(objectString, clazz);
    }

    public void setList(String key, Object value, long timeout) {
        try {
            redisTemplate.opsForValue().set(key, JSON.toJSONString(value), timeout, TimeUnit.SECONDS);
        }catch (Exception e) {
            logger.error("redis error", e);
        }
    }

    public Object executeSetScript(List<String> keys, String script, String requestId, String expireTime , Class clazz ) {
        return redisTemplate.execute(new DefaultRedisScript(script, clazz), keys, requestId , expireTime);
    }

    public Object executeDelScript(List<String> keys, String script, String requestId , Class clazz) {
        return redisTemplate.execute(new DefaultRedisScript(script, clazz), keys, requestId);
    }

    public void listRPush(String key,Object value){
        try {
            redisTemplate.opsForList().rightPush(key, JSON.toJSONString(value));
        }catch (Exception e){
            logger.error("redis error key={}", key, e);
        }
    }

    public List<String> listRange(String key){
        try {
            List<String> range = redisTemplate.opsForList().range(key, 0L, -1L);
            return range;
        }catch (Exception e){
            logger.error("redis error key={}", key, e);
        }
        return null;
    }

    /**
     * 提供给业务方法使用
     * 处理num加
     * @param key
     */
    public void handleAddNumCache(String key) {
        boolean exists = exists(key);
        if (exists) {
            this.incr(key);
        }
    }

    /**
     * 提供给业务方法使用
     * 处理num减
     * @param key
     */
    public void handleCutNumCache(String key) {
        boolean exists = exists(key);
        if (exists) {
            this.incrBy(key, -1L);
        }
    }
}
